package com.zhu.queue.impl;

import com.zhu.queue.Queue;

/**
 * 循环队列
 * @author: zhu
 * @date: 2019/1/13 09:15
 */
public class LoopQueue<E> implements Queue<E> {

    private E[] data;//存放元素的数组
    private int front,tail;//队首和队尾
    private int size;//队列中元素个数

    public LoopQueue(int capacity){
        data = (E[]) new Object[capacity+1];
        front = 0;
        tail = 0;
        size = 0;
    }

    public LoopQueue(){
        this(10);
    }

    /** 获取队列容积(数组长度 - 1 ) */
    public int getCapacity(){
        return data.length - 1;
    }

    @Override
    public int getSize() {
        return size;
    }

    @Override
    public boolean isEmpty() {
        return front == tail;
    }

    @Override
    public void enqueue(E e) {
        if ((tail + 1)% data.length == front){//队列已满
            resize(getCapacity() * 2);//给数组扩容
        }
        data[tail] = e;
        tail = (tail + 1) % data.length;
        size ++;
    }

    /** 给数组扩容 */
    private void resize(int newCapacity) {
        E[] newData = (E[]) new Object[newCapacity + 1];
        for (int i=0;i<size;i++){
            newData[i] = data[(i + front) % data.length];
        }
        data = newData;
        front = 0;
        tail = size;
    }

    @Override
    public E dequeue() {
        if (isEmpty()){
            throw new IllegalArgumentException("空队列不能执行出队操作");
        }
        E e = data[front];
        data[front] = null;
        front = (front + 1) % data.length;
        size --;
        if (size == getCapacity() / 4 && getCapacity() /2 != 0){
            resize(getCapacity() / 2);//缩容
        }
        return e;
    }

    @Override
    public E getFront() {
        if (isEmpty()){
            throw new IllegalArgumentException("队列为空");
        }
        return data[front];
    }

    @Override
    public String toString(){
        StringBuilder res = new StringBuilder();
        res.append(String.format("loopQueue: size = %d,capacity = %d\n",size,getCapacity()));
        res.append("front:[");
        for (int i = front;i != tail ; i=(i+1)%data.length){
            res.append(data[i]);
            if ((i+1) % data.length != tail){
                res.append(", ");
            }
        }
        res.append("] tail");
        return res.toString();
    }
}
